import unittest
import random

import JeuDeCarte
import Poker

class DummyCard:
    """
    Classe utilisée dans certains tests unitaires.
    """
    figures = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
    sortes = {'pique': '♠', 'coeur': '♥', 'carreau': '♦', 'trèfle': '♣'}
    def __init__(self, figure, sorte, face_visible=False):
        self.figure = figure
        self.sorte = sorte
        self.face_visible = face_visible


class TP5_2012(unittest.TestCase):
    def setUp(self):
        """
        Tâches à exécuter avant les tests unitaires. Rien dans ce cas ci.
        """
        pass

    def testCarteArgumentsMinusculesMajuscules(self):
        """
        Teste si on peut créer avec succès une carte sans tenir compte de
        la casse (point 1 de l'énoncé)
        """
        listFig = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
        listSortes = ['pique', 'coeur', 'carreau', 'trèfle']

        fig, sorte = random.choice(listFig), random.choice(listSortes)
        carte1 = JeuDeCarte.Carte(fig, sorte, True)
        carte2 = JeuDeCarte.Carte(fig.lower(), sorte.upper(), True)
        sorte2 = ''
        for i in range(len(sorte)):
            if random.random() < 0.5:
                sorte2 += sorte[i].upper()
            else:
                sorte2 += sorte[i]
        carte3 = JeuDeCarte.Carte(fig, sorte2, True)

        self.assertEqual(str(carte1), str(carte2), msg="Les objets JeuDeCarte.Carte"
                                "('{0}', '{1}', True) et JeuDeCarte.Carte('{2}', '{3}', True)"
                                " devraient être identiques, mais votre programme donne '{4}'"
                                " comme représentation de la première et '{5}' comme"
                                " représentation de la seconde. ".format(fig, sorte, 
                                fig.lower(), sorte.upper(), str(carte1), str(carte2)))
        self.assertEqual(str(carte1), str(carte3), msg="Les objets JeuDeCarte.Carte"
                                "('{0}', '{1}', True) et JeuDeCarte.Carte('{2}', '{3}', True)"
                                " devraient être identiques, mais votre programme donne '{4}'"
                                " comme représentation de la première et '{5}' comme"
                                " représentation de la seconde. ".format(fig, sorte, 
                                fig, sorte2, str(carte1), str(carte3)))

    def testCarteAvecFigureInconnue(self):
        """
        Teste si une exception est bien renvoyée lorsque l'on tente de créer
        une carte avec une figure invalide (point 2 de l'énoncé)
        """
        listBad = ['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'L', 'M', 'N',
                     'O', 'P', 'R', 'S', 'T', 'V', 'U', 'X', 'W', 'Y', 'Z']

        badfig = random.choice(listBad)
        self.assertRaisesRegex(ValueError, "figure '"+badfig+"' inconnue", 
                                    JeuDeCarte.Carte, badfig, "pique")
        self.assertRaisesRegex(ValueError, "figure 'JJ' inconnue", 
                                    JeuDeCarte.Carte, 'JJ', 'pique') 

    def testCarteAvecSorteInconnue(self):
        """
        Teste si une exception est bien renvoyée lorsque l'on tente de créer
        une carte avec une sorte invalide (point 3 de l'énoncé)
        """
        sorte = ""
        for i in range(random.randint(1,8)):
            sorte += chr(random.randrange(ord('a'), ord('z')))

        self.assertRaisesRegex(ValueError, "sorte '"+sorte+"' inconnue", 
                                    JeuDeCarte.Carte, 'A', sorte)

    def testPaquetAvecCarteInvalide(self):
        """
        Teste si l'initialisation d'un paquet avec un type de carte invalide
        produit bien une exception de type TypeError (point 4 de l'énoncé)
        """
        expmsg = "le type de carte doit être dérivé de JeuDeCarte.Carte"

        self.assertRaisesRegex(TypeError, expmsg, JeuDeCarte.Paquet, DummyCard)
        
    def testComparaisonPokerAvecAutreType(self):
        """
        Teste si une exception de type TypeError est bien lancée lorsque on
        tente de comparer une donne non dérivée de Poker.Donne
        (point 5 de l'énoncé)
        """

        expmsg = "une donne de poker ne peut être comparée qu'avec une autre donne de poker"
        d1 = Poker.Donne()
        d2 = JeuDeCarte.Donne()
        paquet = JeuDeCarte.Paquet()
        for i in range(5):
            d1.ajouter(paquet.tirer().flipper())
            d2.ajouter(paquet.tirer().flipper())

        self.assertRaisesRegex(TypeError, expmsg, d1.__lt__, d2)

    def testDonnePokerAvecMoinsOuPlusDeCinqCartes(self):
        """
        Teste si une exception de type AssertionError est bien lancée lorsque
        on tente de comparer deux donnes dont une n'a pas exactement cinq
        cartes (point 6 de l'énoncé)
        """

        d1, d2 = Poker.Donne(), Poker.Donne()
        expmsg = "pour pouvoir être évaluée, une donne doit posséder 5 cartes"

        self.assertRaisesRegex(AssertionError, expmsg, d1.__lt__, d2)
        self.assertRaisesRegex(AssertionError, expmsg, d1.__gt__, d2)
        self.assertRaisesRegex(AssertionError, expmsg, d1.__eq__, d2)
        self.assertRaisesRegex(AssertionError, expmsg, d1.__le__, d2)
        self.assertRaisesRegex(AssertionError, expmsg, d1.__ge__, d2)
        self.assertRaisesRegex(AssertionError, expmsg, d1.__ne__, d2)

        paquet = JeuDeCarte.Paquet()
        for i in range(5):
            d1.ajouter(paquet.tirer().flipper())
        self.assertRaisesRegex(AssertionError, expmsg, d1.__lt__, d2)

        for i in range(6):
            d2.ajouter(paquet.tirer().flipper())
        self.assertRaisesRegex(AssertionError, expmsg, d1.__lt__, d2)
        
    def testPokerAvecCartesSemblables(self):
        """
        Teste si une donne avec une carte répétée est bien inférieure à toute
        autre donne valide (point 7 de l'énoncé).
        """
        paquet = JeuDeCarte.Paquet()
        d1 = Poker.Donne()
        d2 = Poker.Donne()
        
        d1.ajouter(JeuDeCarte.Carte('5', 'pique', True))
        d1.ajouter(JeuDeCarte.Carte('A', 'carreau', True))
        d1.ajouter(JeuDeCarte.Carte('3', 'pique', True))
        d1.ajouter(JeuDeCarte.Carte('9', 'coeur', True))
        d1.ajouter(JeuDeCarte.Carte('3', 'pique', True))
        
        d2.ajouter(JeuDeCarte.Carte('A', 'coeur', True))
        d2.ajouter(JeuDeCarte.Carte('Q', 'trèfle', True))
        d2.ajouter(JeuDeCarte.Carte('3', 'coeur', True))
        d2.ajouter(JeuDeCarte.Carte('K', 'pique', True))
        d2.ajouter(JeuDeCarte.Carte('2', 'trèfle', True))
        
        random.shuffle(d1.cartes)
        random.shuffle(d2.cartes)
        
        self.assertTrue(d1 < d2, msg="La donne {} devrait être considérée inférieure à {}"
                                    " car elle contient deux fois la même carte, mais votre"
                                    " classe Poker.Donne ne l'a pas donnée comme"
                                    " inférieure".format(d1, d2))
        self.assertFalse(d2 < d1, msg="La donne {} devrait être considérée supérieure à {}"
                                    " car la seconde contient deux fois la même carte, mais"
                                    " votre classe Poker.Donne l'a pas donnée comme"
                                    " inférieure".format(d2, d1))

    
 
if __name__ == '__main__':
    # Programme principal
    # Lance les unit tests
    unittest.main()